package com.example.airhockey2

import android.content.Context
import android.opengl.GLES30.*
import android.opengl.GLSurfaceView
import java.io.BufferedReader
import java.io.InputStreamReader
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10

class AirHockeyView(context: Context) : GLSurfaceView(context) {
    init {
        setEGLContextClientVersion(3) // 设置 OpenGL ES 3.0
        setRenderer(AirHockeyRenderer())
    }

    private inner class AirHockeyRenderer : Renderer {
        private var program = 0

        private lateinit var vertexBuffer: FloatBuffer

        private val tableVerticesWithTriangles: FloatArray = floatArrayOf(
            // Order of coordinates: X, Y, R, G, B
            
            // Triangle Fan
               0f,    0f,   1f,   1f,   1f,
            -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,            
             0.5f, -0.5f, 0.7f, 0.7f, 0.7f,
             0.5f,  0.5f, 0.7f, 0.7f, 0.7f,
            -0.5f,  0.5f, 0.7f, 0.7f, 0.7f,
            -0.5f, -0.5f, 0.7f, 0.7f, 0.7f,

            // Line 1
            -0.5f, 0f, 1f, 0f, 0f,
             0.5f, 0f, 1f, 0f, 0f,

            // Mallets
            0f, -0.25f, 0f, 0f, 1f,
            0f,  0.25f, 1f, 0f, 0f
        );

        override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
            glClearColor(0.0f, 0.0f, 0.0f, 1.0f)

            program = createProgram(loadShader(GL_VERTEX_SHADER, "simple_vertex_shader.glsl"),
                loadShader(GL_FRAGMENT_SHADER, "simple_fragment_shader.glsl"))

            // Initialize the vertex buffer
            vertexBuffer = ByteBuffer.allocateDirect(tableVerticesWithTriangles.size * Float.SIZE_BYTES)
                            .order(ByteOrder.nativeOrder())
                            .asFloatBuffer()
            vertexBuffer.put(tableVerticesWithTriangles)

            vertexBuffer.position(0)
            glVertexAttribPointer(0, 2, GL_FLOAT,
                false, 5 * Float.SIZE_BYTES, vertexBuffer);
            glEnableVertexAttribArray(0);

            vertexBuffer.position(2)
            glVertexAttribPointer(1, 3, GL_FLOAT,
                false, 5 * Float.SIZE_BYTES, vertexBuffer);
            glEnableVertexAttribArray(1);
        }

        override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
            glViewport(0, 0, width, height)
        }

        override fun onDrawFrame(gl: GL10?) {
            glClear(GL_COLOR_BUFFER_BIT)

            glUseProgram(program)

            // Draw the table.        
            glDrawArrays(GL_TRIANGLE_FAN, 0, 6);

            // Draw the center dividing line.        
            glDrawArrays(GL_LINES, 6, 2);

            // Draw the first mallet.        
            glDrawArrays(GL_POINTS, 8, 1);

            // Draw the second mallet.
            glDrawArrays(GL_POINTS, 9, 1);
        }

        private fun loadShader(type: Int, filename: String): Int {
            val shaderSource = readShaderFileFromAssets(context, filename)
            val shader = glCreateShader(type)
            glShaderSource(shader, shaderSource)
            glCompileShader(shader)
            val compiled = IntArray(1)
            glGetShaderiv(shader, GL_COMPILE_STATUS, compiled, 0)
            if (compiled[0] == 0) {
                glDeleteShader(shader)
                throw RuntimeException("Could not compile shader: $filename")
            }
            return shader
        }

        private fun createProgram(vertexShader: Int, fragmentShader: Int): Int {
            val program = glCreateProgram()
            glAttachShader(program, vertexShader)
            glAttachShader(program, fragmentShader)
            glLinkProgram(program)
            val linkStatus = IntArray(1)
            glGetProgramiv(program, GL_LINK_STATUS, linkStatus, 0)
            if (linkStatus[0] == 0) {
                glDeleteProgram(program)
                throw RuntimeException("Could not link program")
            }
            return program
        }

        private fun readShaderFileFromAssets(context: Context, filename: String): String {
            val reader = BufferedReader(InputStreamReader(context.assets.open(filename)))
            val builder = StringBuilder()
            var line: String?
            while (reader.readLine().also { line = it } != null) {
                builder.append(line).append("\n")
            }
            reader.close()
            return builder.toString()
        }


    }
}